// Copyright 2017 Baidu Inc. All Rights Reserved.
// Author: Zhang Leliang (zhangleliang@baidu.com)
//
// Description: the implementation of baidu timer on mbed os

#include "baidu_timer_interface.h"
#include "rtos.h"
#include "duer_log.h"
#include "heap_monitor.h"

typedef struct _baidu_timer_t_mbed {
    baidu_timer_callback          timer_callback;
    baidu_timer_release_priv_data timer_priv_data_release;
    baidu_timer_type              timer_type;
    void*                         priv_data;
    int                           interval;
    rtos::RtosTimer*              timer;
} *baidu_timer_p;

baidu_timer_t baidu_timer_create(baidu_timer_callback timer_callback,
                                 baidu_timer_release_priv_data timer_priv_data_release,
                                 baidu_timer_type timer_type,
                                 void* priv_data,
                                 int interval) {
    baidu_timer_p timer = NULL;
    if (timer_callback == NULL) {
        DUER_LOGW("timer_callback is NULL, won't create timer");
        return NULL;
    }
    os_timer_type type = osTimerOnce;
    switch (timer_type) {
    case TIMER_TYPE_ONCE:
        type = osTimerOnce;
        break;
    case TIMER_TYPE_PERIODIC:
        type = osTimerPeriodic;
        break;
    default:
        DUER_LOGW("use default timer type : TIMER_TYPE_ONCE!!");
        break;
    }
    timer = (baidu_timer_p)MALLOC(sizeof(_baidu_timer_t_mbed), UTILITY);
    if (timer == NULL) {
        DUER_LOGE("malloc fail!!");
        return NULL;
    }
    timer->timer_callback = timer_callback;
    timer->timer_priv_data_release = timer_priv_data_release;
    timer->timer_type = timer_type;
    timer->priv_data = priv_data;
    timer->interval = interval;
    timer->timer = NEW(UTILITY) rtos::RtosTimer(priv_data, timer_callback, type);
    DUER_LOGV("create the timer:%p!", timer);
    return timer;
}

int baidu_timer_start(baidu_timer_t timer) {
    if (timer == NULL) {
        DUER_LOGW("timer is NULL!");
        return TIMER_RET_INVALID_PARAM;
    }
    DUER_LOGD("try to start the timer:%p!", timer);
    baidu_timer_p pTimer = (baidu_timer_p)timer;
    osStatus status = pTimer->timer->start(pTimer->interval);
    if (status != osOK) {
        DUER_LOGE("start timer fail, status:0x%x!", status);
        return TIMER_RET_INTERNAL_ERR;
    }
    return TIMER_RET_OK;
}

int baidu_timer_stop(baidu_timer_t timer) {
    if (timer == NULL) {
        DUER_LOGW("timer is NULL!");
        return TIMER_RET_INVALID_PARAM;
    }
    DUER_LOGD("try to stop the timer:%p!", timer);
    baidu_timer_p pTimer = (baidu_timer_p)timer;
    osStatus status = pTimer->timer->stop();
    if (status != osOK && status != osErrorResource) {
        DUER_LOGE("stop timer fail, status:0x%x!", status);
        return TIMER_RET_INTERNAL_ERR;
    }
    return TIMER_RET_OK;
}

int baidu_timer_destroy(baidu_timer_t timer) {
    if (timer == NULL) {
        DUER_LOGW("timer is NULL!");
        return TIMER_RET_INVALID_PARAM;
    }
    DUER_LOGD("destroy the timer:%p!", timer);
    baidu_timer_p pTimer = (baidu_timer_p)timer;
    if (pTimer->timer) {
        delete pTimer->timer;
        pTimer->timer = NULL;
    }

    if (pTimer->priv_data != NULL) {
        if (pTimer->timer_priv_data_release != NULL) {
            pTimer->timer_priv_data_release(pTimer->priv_data);
        }
        pTimer->priv_data = NULL;
    }
    FREE(pTimer);
    return TIMER_RET_OK;
}

